package com.hup.sidebar.framework.model;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import com.hup.sidebar.framework.model.SpFieldHandler.SpField;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author hugan
 * @date 2025/11/14
 */
@SuppressWarnings("unchecked")
public class BaseConfig {
    private static final String TAG = BaseConfig.class.getSimpleName();

    public SharedPreferences getSp(Context context) {
        Class<? extends BaseConfig> clz = getClass();//实现类的class
        return context.getSharedPreferences(clz.getSimpleName(), Context.MODE_PRIVATE);
    }

    /**
     * 从 SharedPreferences 中读取字段并赋值, 处理缺省值
     *
     * @param isReset true-全部使用缺省值
     * @apiNote 如果是多级继承, 需改造
     */
    public <T extends BaseConfig> T loadAll(Context context, boolean isReset) throws ConfigException {
        try {
            SharedPreferences sp = getSp(context);
            Class<? extends BaseConfig> clz = getClass();//实现类的class
            Map<String, SpFieldHandler> mapper = getFieldMapper(clz);//全部配置字段
            for (SpFieldHandler handler : mapper.values()) {
                if (!isReset) {
                    handler.load(this, sp);//加载配置
                } else {
                    handler.reset(this);//设置成默认值
                }
            }
            return (T) this;
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    public <T extends BaseConfig> T loadAll(Context context) throws ConfigException {
        return loadAll(context, false);
    }

    public void reset(String fieldName) throws ConfigException {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            handler.reset(this);
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    public void reset(String fieldName, SharedPreferences sp) throws ConfigException {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            handler.reset(this, sp);
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    public <T> T getDefault(String fieldName) {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            return (T) handler.getDefault();
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    public <T> T get(String fieldName) {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            return (T) handler.get(this);
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    /**
     * 赋值
     */
    public void set(String fieldName, Object value) {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            handler.set(this, value);
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    /**
     * 赋值&保存
     */
    public void set(String fieldName, Object value, SharedPreferences sp) {
        try {
            SpFieldHandler handler = getFieldMapper(getClass()).get(fieldName);
            assert handler != null;
            handler.set(this, value, sp);
        } catch (Exception e) {
            throw new ConfigException(e);
        }
    }

    public static class ConfigException extends RuntimeException {
        public ConfigException(Exception e) {
            super(e);
        }
    }

    private static final HashMap<Class<?>, WeakReference<Map<String, SpFieldHandler>>> CLZ_MAP = new HashMap<>();

    /**
     * @return 允许被回收的弱引用
     */
    public static Map<String, SpFieldHandler> getFieldMapper(Class<?> clz) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        WeakReference<Map<String, SpFieldHandler>> reference = CLZ_MAP.get(clz);
        Map<String, SpFieldHandler> map = reference != null ? reference.get() : null;
        if (map == null) {
            Log.i(TAG, "getFieldMapper 初始化:" + clz + ", 首次=" + (reference == null));
            map = buildMapper(clz);
            reference = new WeakReference<>(map);
            CLZ_MAP.put(clz, reference);
        }
        return map;
    }

    /**
     * @apiNote 如果是多级继承, 需改造
     */
    public static Map<String, SpFieldHandler> buildMapper(Class<?> clz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Map<String, SpFieldHandler> res = new HashMap<>();
        Field[] fields = clz.getDeclaredFields();//实现类的全部字段,不含父类字段
        for (Field field : fields) {
            SpField spField = field.getAnnotation(SpField.class);
            if (spField == null) continue;
            String fieldName = field.getName();
            SpFieldHandler handler = spField.handler().getDeclaredConstructor().newInstance();
            handler.init(fieldName, field, spField);
            res.put(fieldName, handler);
        }
        return res;
    }

}
